﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Frogism.Core;
using Frogism.Data;

namespace Frogism.Domain {
 
    
    public class MoneyManager : ManagerBase<Account,IAccount> {
        private Core.IAccountLoader _Loader;
        public override ILoader<Account,IAccount> Loader {
          get {
            if(_Loader == null) {
              _Loader = new Data._2.AccountRepository();
            }
            return _Loader;
          }
        }
        private decimal cashTotalChange = 0;
        private decimal retirementTotalChange = 0;
        private decimal investmentTotalChange = 0;
        private decimal debitTotalChange = 0;
        private decimal mortgageTotalChange = 0;

        private Boolean IsInvestment(int AccountType) {
          switch (AccountType) {
            case DBConst.AccountTypeInvestment:
            case DBConst.AccountTypeRetirement:
              return true;
            default:
              return false;
          }
        }
        public Collection<IAccount> GetInvestmentAccounts() {
          return GetAll().Where(a => IsInvestment(a.AccountType)).ToCollection() ;

        }
        private Balance GetProgressByYear(IEnumerable<IAccount> accounts, int year) {
          Balance item = new Balance();
          if (year == 2007) {
            item.BalanceDate = Account.BUDGET_START_DATE;
          } else {
            item.BalanceDate = new DateTime(year, 1, 1, 0, 0, 0);
          }

          foreach (IAccount account in accounts) {
            decimal change; //, balance;



            change = (from t in account.Transactions
                      where t.TransactionDate.Year == year
                      && t.TransactionDate >= item.BalanceDate
                      select t.Value).Sum();

            //balance = (from t in account.Transactions
            //           where t.TransactionDate < item.BalanceDate
            //           select t.Value).Sum();




            switch (account.AccountType) {
              case DBConst.AccountTypeChecking:
              case DBConst.AccountTypeSavings:
                item.Cash.Change += change;
                cashTotalChange += change;
                item.Cash.TotalChange = cashTotalChange;
                break;
              case DBConst.AccountTypeInvestment:
                item.Investment.Change += change;
                investmentTotalChange += change;
                item.Investment.TotalChange = investmentTotalChange;
                break;
              case DBConst.AccountTypeRetirement:
                item.Retirement.Change += change;
                retirementTotalChange += change;
                item.Retirement.TotalChange = retirementTotalChange;
                break;
                case DBConst.AccountTypeMortgage:
                item.Mortgage.Change += change;
                mortgageTotalChange += change;
                item.Mortgage.TotalChange = mortgageTotalChange;

                break;
              case DBConst.AccountTypeCreditCard:
                item.Debit.Change += change;
                debitTotalChange += change;
                item.Debit.TotalChange = debitTotalChange;
                break;
            }

            item.Liquid.Change = item.Cash.Change + item.Debit.Change;
            item.Liquid.TotalChange = item.Cash.TotalChange + item.Debit.TotalChange;

            item.NetWorth.Change = item.Liquid.Change + item.Retirement.Change + item.Investment.Change + item.Mortgage.Change;
            item.NetWorth.TotalChange = item.Liquid.TotalChange + item.Retirement.TotalChange + item.Investment.TotalChange + item.Mortgage.TotalChange;
          }

          return item;
        }
        private Balance GetProgressByMonth(IEnumerable<IAccount> accounts,int month, int year){
          Balance item = new Balance();
          item.BalanceDate = new DateTime(year, month, 1, 0, 0, 0);

          
          foreach(IAccount account in accounts) {
            decimal change, balance;


            change = (from t in account.Transactions
                      where t.TransactionDate.Month == month && t.TransactionDate.Year == year
                      select t.Value).Sum();
            balance = (from t in account.Transactions
                       where t.TransactionDate < item.BalanceDate
                       select t.Value).Sum();




            switch(account.AccountType) {
              case DBConst.AccountTypeChecking:
              case DBConst.AccountTypeSavings:
                item.Cash.Change += change;
                cashTotalChange += change;
                item.Cash.TotalChange = cashTotalChange;
                break;
              case DBConst.AccountTypeInvestment:
                item.Investment.Change += change;
                investmentTotalChange += change;
                item.Investment.TotalChange = investmentTotalChange;
                break;
              case DBConst.AccountTypeRetirement:
                item.Retirement.Change += change;
                retirementTotalChange += change;
                item.Retirement.TotalChange = retirementTotalChange;
                break;
              case DBConst.AccountTypeCreditCard:
                item.Debit.Change += change;
                debitTotalChange += change;
                item.Debit.TotalChange = debitTotalChange;
                item.Debit.Value += balance;
                break;
              case DBConst.AccountTypeMortgage:
                item.Mortgage.Change += change;
                mortgageTotalChange += change;
                item.Mortgage.TotalChange = mortgageTotalChange;
                break;
            }

            item.Liquid.Change = item.Cash.Change + item.Debit.Change;
            item.Liquid.TotalChange = item.Cash.TotalChange + item.Debit.TotalChange;

            item.NetWorth.Change = item.Liquid.Change + item.Retirement.Change + item.Investment.Change + item.Mortgage.Change;
            item.NetWorth.TotalChange = item.Liquid.TotalChange + item.Retirement.TotalChange + item.Investment.TotalChange + item.Mortgage.TotalChange;
          }
        
          return item;
        }
        private Balance GetProgressByWeek(IEnumerable<IAccount> accounts, DateTime dateOfWeek)
        {
            Balance item = new Balance();
            item.BalanceDate = dateOfWeek.StartOfWeek();
            DateTime weekEnd = dateOfWeek.EndOfWeek();

            foreach (IAccount account in accounts)
            {
                decimal change, balance;


                change = (from t in account.Transactions
                          where t.TransactionDate >=  item.BalanceDate && t.TransactionDate <= weekEnd
                          select t.Value).Sum();
                balance = (from t in account.Transactions
                           where t.TransactionDate < item.BalanceDate
                           && t.TransactionDate.Year == item.BalanceDate.Year
                           select t.Value).Sum();




                switch (account.AccountType)
                {
                    case DBConst.AccountTypeChecking:
                    case DBConst.AccountTypeSavings:
                        item.Cash.Change += change;
                        cashTotalChange += change;
                        item.Cash.TotalChange = cashTotalChange;
                        break;
                    case DBConst.AccountTypeInvestment:
                        item.Investment.Change += change;
                        investmentTotalChange += change;
                        item.Investment.TotalChange = investmentTotalChange;
                        break;
                    case DBConst.AccountTypeRetirement:
                        item.Retirement.Change += change;
                        retirementTotalChange += change;
                        item.Retirement.TotalChange = retirementTotalChange;
                        break;
                    case DBConst.AccountTypeCreditCard:
                        item.Debit.Change += change;
                        debitTotalChange += change;
                        item.Debit.TotalChange = debitTotalChange;
                        break;
                }

                item.Liquid.Change = item.Cash.Change + item.Debit.Change;
                item.Liquid.TotalChange = item.Cash.TotalChange + item.Debit.TotalChange;

                item.NetWorth.Change = item.Liquid.Change + item.Retirement.Change + item.Investment.Change;
                item.NetWorth.TotalChange = item.Liquid.TotalChange + item.Retirement.TotalChange + item.Investment.TotalChange;
            }

            return item;
        }

        private IAccountLoader GetAccountLoader()
        {
            return (IAccountLoader)Loader;
        }
        public Collection<Balance> GetProgressByYear() {
          Collection<Balance> list = new Collection<Balance>();
          int currentYear = DateTime.Now.Year;

          IAccountLoader al = GetAccountLoader();
          IEnumerable<IAccount> accounts = al.GetAll();
          DateTime tempDate = Core.Account.BUDGET_START_DATE;
          
          while (tempDate < DateTime.Now.AddYears(1)) {
           
            list.Add(GetProgressByYear(accounts, tempDate.Year));

            tempDate = tempDate.AddYears(1);
          }
          
          return list.OrderByDescending(t => t.BalanceDate).ToCollection<Balance>();
          ;
        }
        public Collection<Balance> GetProgressByWeek()
        {
            Collection<Balance> list = new Collection<Balance>();
            int currentYear = DateTime.Now.Year;

            IAccountLoader al = GetAccountLoader();
            IEnumerable<IAccount> accounts = al.GetAll();
            DateTime tempDate = Core.Account.BUDGET_START_DATE;
            int LastYear = -1;
            while (tempDate < DateTime.Now)
            {
                if (LastYear != tempDate.Year)
                {
                    this.debitTotalChange = 0;
                    this.cashTotalChange = 0;
                    this.retirementTotalChange = 0;
                    this.investmentTotalChange = 0;
                }
                LastYear = tempDate.Year;
                list.Add(GetProgressByWeek(accounts, tempDate));

                tempDate = tempDate.AddDays(7);
            }
            return list.OrderByDescending(t => t.BalanceDate).ToCollection<Balance>();
            ;
        }
        public Collection<Balance> GetProgressByMonth() {
          Collection<Balance> list = new Collection<Balance>();
          int currentYear = DateTime.Now.Year;

          IAccountLoader al = GetAccountLoader();
          IEnumerable<IAccount> accounts = al.GetAll();
          DateTime tempDate = Core.Account.BUDGET_START_DATE;
          int LastYear = -1;
          while (tempDate < DateTime.Now) {
            if (LastYear != tempDate.Year) {
              this.debitTotalChange = 0;
              this.cashTotalChange = 0;
              this.retirementTotalChange = 0;
              this.investmentTotalChange = 0;
              this.mortgageTotalChange = 0;
            }
            LastYear = tempDate.Year;
            list.Add(GetProgressByMonth(accounts, tempDate.Month, tempDate.Year));

            tempDate = tempDate.AddMonths(1);
          }
          return list.OrderByDescending(t => t.BalanceDate).ToCollection<Balance>();
          ;
        }
        public Collection<INetWorth> GetNetWorth(IEnumerable<IAccount> accounts)
        {
          
          Collection<INetWorth> items = new Collection<INetWorth>();
          INetWorth item = NetWorthItem.CreateCash(accounts);
          items.Add(item);
          items.Add(NetWorthItem.CreateDebit(accounts));
          items.Add(NetWorthItem.CreateLiquid(accounts));
          items.Add(NetWorthItem.CreateInvestment(accounts));
          items.Add(NetWorthItem.CreateMortgage(accounts));
          items.Add(NetWorthItem.CreateRetirement(accounts));
          items.Add(NetWorthItem.CreateNetWorth(accounts));

          return items;
        }
        public static Collection<ITransaction> FilterRecent(IAccount account) {
          return (from t in account.Transactions
                  where ((TimeSpan)DateTime.Now.Subtract(t.TransactionDate)).Days < 15
                  && t.IsConfirmed
                  select t).OrderByDescending(t=>t.TransactionDate).ToCollection<ITransaction>();
        }


        public static Collection<ITransaction> FilterUnconfirmed(IAccount account) {
          return (from t in account.Transactions
                  where !t.IsConfirmed
                  select t).OrderByDescending(t => t.TransactionDate).ToCollection<ITransaction>();
      
        }
        public Collection<IObjectNameBase> GetAccountBasic() {
          ObjectNameBaseLoader loader = new ObjectNameBaseLoader();
          return loader.GetAll("Account");
        }
        
        public Collection<IObjectNameBase> GetTransactionTypeBasic() {
          ObjectNameBaseLoader loader = new ObjectNameBaseLoader();
          return loader.GetAll("TransactionType");
        }
    }
}
